import org.junit.Assert;
import org.junit.Test;

public class 测试解释器 {

    public String 执行(String 源码) {
        // 1. 汇编
        var 汇编器 = 字节码汇编器.汇编(源码);
        var 字节码输出 = 字节码汇编器.输出字节码(汇编器.字节码, 汇编器.取字节码尺寸());
        System.out.println("字节码:");
        System.out.println(字节码输出);

        // 2. 反汇编
        System.out.println("反汇编：");
        var 反汇编 = new 反汇编器(汇编器.字节码, 汇编器.取字节码尺寸(), 汇编器.常量池.toArray());
        反汇编.反汇编();
        System.out.println(反汇编.反汇编输出);

        // 3. 执行
        System.out.println("\n执行：");
        var 解释器 = new 解释器();
        解释器.加载(汇编器.字节码, 汇编器.取字节码尺寸(), 汇编器.常量池.toArray(), 汇编器.入口函数, 汇编器.数据尺寸);
        解释器.执行();

        if (解释器.输出 == null) return null;
        var 输出 = 解释器.输出.toString();
        System.out.println(标蓝(输出));
        return 输出;
    }

    private static String 标蓝(String 文本) {
        return "\u001B[34m" + 文本 + "\u001B[0m";
    }

    @Test
    public void 测试print() {
        var 源码 = """
                .def main: args=0, locals=1
                    iconst r1, 1
                	print r1
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "1");
    }

    @Test
    public void 测试iadd() {
        var 源码 = """
                .def main: args=0, locals=3
                    iconst r1, 1
                    iconst r2, 2
                    iadd r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "3");
    }

    @Test
    public void 测试isub1() {
        var 源码 = """
                .def main: args=0, locals=3
                    iconst r1, 1
                    iconst r2, 2
                    isub r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "-1");
    }

    @Test
    public void 测试isub2() {
        var 源码 = """
                .def main: args=0, locals=3
                    iconst r1, 2
                    iconst r2, 1
                    isub r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "1");
    }

    @Test
    public void 测试imul() {
        var 源码 = """
                .def main: args=0, locals=3
                    iconst r1, 2
                    iconst r2, 3
                    imul r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "6");
    }

    @Test
    public void 测试ilt1() {
        var 源码 = """
                .def main: args=0, locals=3
                    iconst r1, 1
                    iconst r2, 2
                    ilt r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "true");
    }

    @Test
    public void 测试ilt2() {
        var 源码 = """
                .def main: args=0, locals=3
                    iconst r1, 2
                    iconst r2, 1
                    ilt r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "false");
    }

    @Test
    public void 测试ieq1() {
        var 源码 = """
                .def main: args=0, locals=3
                    iconst r1, 2
                    iconst r2, 1
                    ieq r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "false");
    }

    @Test
    public void 测试ieq2() {
        var 源码 = """
                .def main: args=0, locals=3
                    iconst r1, 1
                    iconst r2, 1
                    ieq r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "true");
    }

    @Test
    public void 测试feq1() {
        var 源码 = """
                .def main: args=0, locals=3
                    fconst r1, 3.14
                    fconst r2, 3.14
                    feq r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "true");
    }

    @Test
    public void 测试feq2() {
        var 源码 = """
                .def main: args=0, locals=3
                    fconst r1, 3.14
                    fconst r2, 3.1415
                    feq r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "false");
    }

    @Test
    public void 测试fadd() {
        var 源码 = """
                .def main: args=0, locals=3
                    fconst r1, 1.1
                    fconst r2, 2.2
                    fadd r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(Float.parseFloat(结果), 3.3, 0.0001);
    }

    @Test
    public void 测试fsub1() {
        var 源码 = """
                .def main: args=0, locals=3
                    fconst r1, 1.1
                    fconst r2, 2.2
                    fsub r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(Float.parseFloat(结果), -1.1, 0.0001);
    }

    @Test
    public void 测试fsub2() {
        var 源码 = """
                .def main: args=0, locals=3
                    fconst r1, 2.2
                    fconst r2, 1.1
                    fsub r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(Float.parseFloat(结果), 1.1, 0.0001);
    }

    @Test
    public void 测试fmul() {
        var 源码 = """
                .def main: args=0, locals=3
                    fconst r1, 0.5
                    fconst r2, 1.8
                    fmul r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(Float.parseFloat(结果), 0.9, 0.0001);
    }

    @Test
    public void 测试flt1() {
        var 源码 = """
                .def main: args=0, locals=3
                    fconst r1, 0.5
                    fconst r2, 1.8
                    flt r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "true");
    }

    @Test
    public void 测试flt2() {
        var 源码 = """
                .def main: args=0, locals=3
                    fconst r1, 1.8
                    fconst r2, 0.5
                    flt r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "false");
    }

    @Test
    public void 测试flt3() {
        var 源码 = """
                .def main: args=0, locals=3
                    fconst r1, 0.5
                    fconst r2, 0.5
                    flt r1, r2, r3
                	print r3
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "false");
    }

    @Test
    public void 测试itof() {
        var 源码 = """
                .def main: args=0, locals=2
                    iconst r1, 2
                    itof r1, r2
                	print r2
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "2");
    }

    @Test
    public void 测试call() {
        var 源码 = """
                .def main: args=0, locals=2
                    iconst r1, 1
                    iconst r2, 2
                    iconst r0, 1
                    call add(), r1  ; 结果返回到 r0; 传入参数：[r1,r2]
                	print r0
                	halt
                
                .def add: args=2, locals=0
                    iadd r1, r2, r0
                    ret
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "3");
    }

    @Test
    public void 测试br() {
        var 源码 = """
                .def main: args=0, locals=1
                    iconst r1, 1
                    br a
                    iconst r1, 2
                a:
                	print r1
                	halt
                
            
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "1");
    }

    @Test
    public void 测试brt1() {
        var 源码 = """
                .def main: args=0, locals=3
                    iconst r1, 1
                    iconst r2, 2
                    ilt r1, r2, r3  ; r3 = r1 < r2
                    brt r3, a
                    print r1
                	halt
                a:
                	print r2
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "2");
    }

    @Test
    public void 测试brt2() {
        var 源码 = """
                .def main: args=0, locals=3
                    iconst r1, 20
                    iconst r2, 10
                    ilt r1, r2, r3  ; r3 = r1 < r2
                    brt r3, a
                    print r1
                	halt
                a:
                	print r2
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "20");
    }

    @Test
    public void 测试brf1() {
        var 源码 = """
                .def main: args=0, locals=3
                    iconst r1, 1
                    iconst r2, 2
                    ilt r1, r2, r3  ; r3 = r1 < r2
                    brf r3, a
                    print r1
                	halt
                a:
                	print r2
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "1");
    }

    @Test
    public void 测试brf2() {
        var 源码 = """
                .def main: args=0, locals=3
                    iconst r1, 20
                    iconst r2, 10
                    ilt r1, r2, r3  ; r3 = r1 < r2
                    brf r3, a
                    print r1
                	halt
                a:
                	print r2
                	halt
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "10");
    }

    @Test
    public void 测试cconst() {
        var 源码 = """
                .def main: args=0, locals=1
                    cconst r1, 'a'
                    print r1
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "a");
    }

    @Test
    public void 测试iconst() {
        var 源码 = """
                .def main: args=0, locals=1
                    iconst r1, -123
                    print r1
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "-123");
    }

    @Test
    public void 测试fconst() {
        var 源码 = """
                .def main: args=0, locals=1
                    fconst r1, -3.14
                    print r1
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "-3.14");
    }

    @Test
    public void 测试sconst() {
        var 源码 = """
                .def main: args=0, locals=1
                    sconst r1, "Hello, world!"
                    print r1
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "Hello, world!");
    }

    @Test
    public void 测试gload() {
        var 源码 = """
                .globals 1
                .def main: args=0, locals=1
                    iconst r1, 123
                    gstore r1, 0
                    iconst r1, 456
                    gload r1, 0
                    print r1
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "123");
    }

    @Test
    public void 测试fload() {
        var 源码 = """
                .def main: args=0, locals=2
                    struct r1, 1    ; 定义有1个字段的 struct
                    iconst r2, 123  ; r2 = 123
                    fstore r2, r1, 0 ; r1[0] = r2
                    iconst r2, 456  ; r2 = 456
                    fload r2, r1, 0  ; r2 = r1[0]
                    print r2
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "123");
    }

    @Test
    public void 测试move() {
        var 源码 = """
                .def main: args=0, locals=2
                    iconst r1, 100
                    iconst r2, 200
                    move r1, r2
                    print r2
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "100");
    }

    @Test
    public void 测试null() {
        var 源码 = """
                .def main: args=0, locals=1
                    iconst r1, 100
                    null r1
                    print r1
                """;

        var 结果 = 执行(源码);
        Assert.assertEquals(结果, "null");
    }
}